package com.haochang.chunkvod.tools.vod.event;

import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Logger;

/**
 * base class of Observable
 * 
 * @author xingbo.jie
 */
@SuppressWarnings("unused")
public abstract class EventObservable
{
	/**
	 * 是否使用代理模式<br>
	 * 代理模式不分模块。eventId不需要根据模块做识别
	 */
	private final static boolean USE_PROXY = true;

	/* *****************************************************
	 * 非代理模式适用，代理模式忽略本解释
	 * events rule:
	 * all EventObservable who want to provide events should modify this file and add a event_family_xxx value below.
	 * the high 2 bytes of event_family_xxx is the event family mask, in other words,
	 * a module can have 0x10000 events without conflicting with other modules' events.
	 * the value No Need to be bit-flag.
	 * ****************************************************/
	public final static int EVENT_FAMILY_MASK = 0xffff0000;

	public final static int EVENT_FAMILY_STEP = 0x10000;

	private final OneToManyHashMap<Integer, EventObserver> observers = new OneToManyHashMap<Integer, EventObserver>();

	public EventObservable()
	{
	}

	/**
	 * add a listener who care evenId
	 * 
	 * @param eventId
	 * @param listener
	 */
	public void addListener(int eventId, EventObserver listener) throws InvalidParameterException
	{
		if (!USE_PROXY && (eventId & EVENT_FAMILY_MASK) != getEventFamily())
		{
			throw new InvalidParameterException("i dont know eventId " + eventId);
		}
		observers.put(eventId, listener);
	}

	/**
	 * has any listener care this eventId
	 * 
	 * @param eventId
	 * @return
	 */
	public boolean hasListener(int eventId)
	{
		return !isEmpty(observers.get(eventId));
	}

	/**
	 * remove one listener from the observers of eventId
	 * 
	 * @param eventId
	 * @param listener
	 */
	public void removeListener(int eventId, EventObserver listener) throws InvalidParameterException
	{
		if (!USE_PROXY && (eventId & EVENT_FAMILY_MASK) != getEventFamily())
		{
			throw new InvalidParameterException("i dont know eventId " + eventId);
		}
		observers.remove(eventId, listener);
	}

	/**
	 * remove the listener from all eventIds
	 * 
	 * @param listener
	 */
	public void removeListener(EventObserver listener)
	{
		observers.removeValue(listener);
	}

	/**
	 * clear the observers of eventId
	 * 
	 * @param eventId
	 */
	public void removeListener(int eventId)
	{
		observers.remove(eventId);
	}

	public void clear()
	{
		observers.clear();
	}

	/**
	 * notify a event was happened by specified sender
	 * 
	 * @param sender
	 * @param eventId
	 * @param args
	 */
	@SuppressWarnings("unchecked")
	protected void notify(Object sender, int eventId, Object... args)
	{
		ArrayList<EventObserver> listeners = observers.get(eventId);
		if (!isEmpty(listeners))
		{
			listeners = (ArrayList<EventObserver>) listeners.clone();
			Iterator<EventObserver> it = listeners.iterator();
			while (it.hasNext())
			{
				it.next().onNotify(sender, eventId, args);
			}
		}
	}

	private boolean isEmpty(List<?> list)
	{
		return list == null || list.size() == 0;
	}

	/**
	 * notify a event was happened by myself
	 * 
	 * @param eventId
	 * @param args
	 */
	protected void notify(int eventId, Object... args)
	{
		notify(this, eventId, args);
	}

	public abstract int getEventFamily();
}
